package com.jxtc.enterprise.delivery.service;

import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jxtc.enterprise.common.constants.DeliveryCostTypeEnum;
import com.jxtc.enterprise.common.entity.DeliveryTask;
import com.jxtc.enterprise.common.mapper.DeliveryTaskMapper;
import com.jxtc.enterprise.common.mapper.DeliveryTaskStoreMapper;
import com.jxtc.enterprise.common.utils.CurrencyUtil;
import com.jxtc.enterprise.common.vo.PaginationResponseVO;
import com.jxtc.enterprise.delivery.dto.historyData.DailyTaskIncomeDTO;
import com.jxtc.enterprise.delivery.dto.historyData.DeliveryTaskWithCompanyDTO;
import com.jxtc.enterprise.delivery.dto.todayTask.TodayStoreOrderDTO;
import com.jxtc.enterprise.delivery.vo.historyData.DailyTaskIncomeDetailVO;
import com.jxtc.enterprise.delivery.vo.historyData.DailyTaskIncomeVO;
import com.jxtc.enterprise.delivery.vo.historyData.DailyTaskOrderDetailVO;
import com.jxtc.enterprise.delivery.vo.historyData.InComeSummaryVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class RiderHistoryDataService {

    private final DeliveryTaskMapper deliveryTaskMapper;
    private final DeliveryTaskStoreMapper deliveryTaskStoreMapper;

    public InComeSummaryVO queryInComeSummary(String riderId) {
        Integer totalIncome = deliveryTaskMapper.queryTotalIncome(riderId);
        Integer monthlyIncome = deliveryTaskMapper.queryMonthlyIncome(riderId, getFirstDayOfMonth(), getLastDayOfMonth());

        // 将数据库中保存的以 "分" 为单位的金额转换成以 "元" 为单位
        int total = totalIncome == null ? 0 : totalIncome;
        int monthly = monthlyIncome == null ? 0 : monthlyIncome;
        String totalIncomeYuan = CurrencyUtil.fenToYuan(total);
        String monthlyIncomeYuan = CurrencyUtil.fenToYuan(monthly);

        return new InComeSummaryVO(totalIncomeYuan, monthlyIncomeYuan);
    }

    /**
     * 获取本月第一天
     *
     * @return yyyy-MM-dd 格式字符串
     */
    private String getFirstDayOfMonth() {
        return LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    /**
     * 获取本月最后一天
     *
     * @return yyyy-MM-dd 格式字符串
     */
    private String getLastDayOfMonth() {
        return LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }


    public PaginationResponseVO<DailyTaskIncomeVO> queryDailyTaskAndIncomeByPage(String riderId, int pageNo, int pageSize) {
        // 1. 构建分页参数
        Page<DailyTaskIncomeDTO> page = new Page<>(pageNo, pageSize);

        // 2. 查询每日配送任务和收入
        Page<DailyTaskIncomeDTO> pageResult = deliveryTaskMapper.pageDailyTaskAndIncome(page, riderId);

        // 3. 转换金额单位：分 -> 元
        List<DailyTaskIncomeVO> records = pageResult.getRecords().stream()
                .map(this::bulidDailyTaskIncomeVO)
                .collect(Collectors.toList());
        return new PaginationResponseVO<>(pageResult.getTotal(), pageResult.getCurrent(), records);
    }

    private DailyTaskIncomeVO bulidDailyTaskIncomeVO(DailyTaskIncomeDTO dto) {
        DailyTaskIncomeVO vo = new DailyTaskIncomeVO();
        vo.setDate(dto.getDate());

        int incomeFen = dto.getIncome() == null ? 0 : dto.getIncome();
        String incomeYuan = CurrencyUtil.fenToYuan(incomeFen);
        vo.setIncome(incomeYuan);

        vo.setTaskCount(dto.getTaskCount());

        // 默认结算状态为 "未结算"
        int settlementStatus = dto.getSettlementStatus() == null ? 1 : dto.getSettlementStatus();
        vo.setSettlementStatus(settlementStatus);

        return vo;
    }


    public List<DailyTaskIncomeDetailVO> queryDailyTaskAndIncomeDetail(String riderId, String date) {
        // 1. 根据配送员 ID 和日期，查询当天在所有的配送任务
        List<DeliveryTaskWithCompanyDTO> deliveryTaskList = deliveryTaskMapper.queryDeliveryTaskWithCompanyByRiderIdAndDate(riderId, date);

        List<String> taskIds = deliveryTaskList.stream()
                .map(DeliveryTaskWithCompanyDTO::getTaskId)
                .collect(Collectors.toList());
        List<String> companyIds = deliveryTaskList.stream()
                .map(DeliveryTaskWithCompanyDTO::getCompanyId)
                .collect(Collectors.toList());

        // 2. 根据配送任务 ID 列表和指定日期，查询当天在所有店铺中的订单数量
        Map<String, List<TodayStoreOrderDTO>> groupedByTaskId = new HashMap<>();
        if (!taskIds.isEmpty()) {
            // 如果配送任务 ID 列表不为空，则查询订单数量；
            // 否则不执行查询操作
            List<TodayStoreOrderDTO> storeOrderDetailList = deliveryTaskStoreMapper.queryTodayStoreOrder(taskIds, companyIds, date);
            // 根据 taskId 分组，方便后续根据配送任务 ID 获取订单数量及店铺信息
            groupedByTaskId = storeOrderDetailList.stream().collect(Collectors.groupingBy(TodayStoreOrderDTO::getTaskId));
        }

        // 3. 遍历配送任务列表，构建每日任务收入详情 VO 列表
        List<DailyTaskIncomeDetailVO> detailVOList = new ArrayList<>();
        for (DeliveryTaskWithCompanyDTO deliveryTask : deliveryTaskList) {
            DailyTaskIncomeDetailVO vo = new DailyTaskIncomeDetailVO();
            vo.setTaskId(deliveryTask.getTaskId());
            vo.setCompanyId(deliveryTask.getCompanyId());
            vo.setCompanyName(deliveryTask.getCompanyName());
            vo.setOrderCount(deliveryTask.getOrderCount());
            vo.setDeliveryStartTime(deliveryTask.getDeliveryStartTime());
            vo.setDeliveryAddress(deliveryTask.getDeliveryAddress());

            // 金额单位转换：分 -> 元
            String commissionInYuan = CurrencyUtil.fenToYuan(deliveryTask.getTotalFee());
            vo.setTaskCommission(commissionInYuan);

            // 根据 taskId 获取订单详情列表，并转换成前端可用的数据类型
            List<DailyTaskOrderDetailVO> orderDetails = groupedByTaskId.getOrDefault(deliveryTask.getTaskId(), Collections.emptyList())
                    .stream()
                    .map(detail -> {
                        DailyTaskOrderDetailVO detailVO = new DailyTaskOrderDetailVO();
                        detailVO.setStoreId(detail.getStoreId());
                        detailVO.setStoreName(detail.getStoreName());
                        detailVO.setStoreOrderCount(detail.getOrderCount());
                        return detailVO;
                    }).collect(Collectors.toList());
            vo.setOrderDetails(orderDetails);

            detailVOList.add(vo);
        }

        return detailVOList;
    }


    public void exportByMonth(String riderId, String month, HttpServletResponse response) {
        // 1. 根据骑手 ID 和月份查询骑手历史数据
        LambdaQueryWrapper<DeliveryTask> queryWrapper = new LambdaQueryWrapper<DeliveryTask>()
                .eq(DeliveryTask::getRiderId, riderId)
                .likeRight(DeliveryTask::getDeliveryDate, month)
                .eq(DeliveryTask::getDeliveryStatus, 2)
                .eq(DeliveryTask::getDelFlag, false)
                .orderByDesc(DeliveryTask::getDeliveryDate, DeliveryTask::getDeliveryStartTime, DeliveryTask::getDeliveryOrder);

        List<DeliveryTask> deliveryTaskList = deliveryTaskMapper.selectList(queryWrapper);
        // 2. 导出 excel 数据
        try (ExcelWriter writer = ExcelUtil.getWriter(true)) {
            // 是否是 excel 的第一页
            boolean firstSheet = true;

            // 构建 excel 中的每行数据
            int idx = 1;
            List<Map<String, Object>> data = new ArrayList<>();
            for (DeliveryTask deliveryTask : deliveryTaskList) {
                // 将订单总金额的单位由 "分" 转换为 "元"
                Integer orderAmount = deliveryTask.getOrderAmount();
                String orderAmountInYuan = CurrencyUtil.fenToYuan(orderAmount);

                // 构造配送费用结算方式，默认 "-"，表示非法的结算方式
                String deliveryCostType = deliveryTask.getDeliveryCostType();
                Integer deliveryCostValue = deliveryTask.getDeliveryCostValue();
                String deliveryCost = "-";
                if (DeliveryCostTypeEnum.PER_ORDER.getName().equals(deliveryCostType)) {
                    String costInYuan = CurrencyUtil.fenToYuan(deliveryCostValue);
                    deliveryCost = String.format("每单 %s 元", costInYuan);
                } else if (DeliveryCostTypeEnum.PERCENTAGE_OF_ORDER.getName().equals(deliveryCostType)) {
                    // 百分比抽成则需要将单位由 "万分之一" 转换为 "百分之一"，即除以 100
                    String percentage = new BigDecimal(deliveryCostValue)
                            .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                            .toString();
                    deliveryCost = String.format("订单金额的 %s%%", percentage);
                } else if (DeliveryCostTypeEnum.FIXED_AMOUNT.getName().equals(deliveryCostType)) {
                    String costInYuan = CurrencyUtil.fenToYuan(deliveryCostValue);
                    deliveryCost = String.format("%s 元包干", costInYuan);
                }

                // 将附加费用、扣款和总佣金单位由 "分" 转换为 "元"
                Integer additionalFee = deliveryTask.getAdditionalFee();
                String additionalFeeInYuan = CurrencyUtil.fenToYuan(additionalFee);

                Integer deductFee = deliveryTask.getDeductFee();
                String deductFeeInYuan = CurrencyUtil.fenToYuan(deductFee);

                Integer totalFee = deliveryTask.getTotalFee();
                String totalFeeInYuan = CurrencyUtil.fenToYuan(totalFee);

                // 将备注信息为空时，默认设置为 "无"
                String note = deliveryTask.getNote() == null || deliveryTask.getNote().isEmpty() ? "无" : deliveryTask.getNote();

                // TODO: 参数过多，考虑是否需要封装成一个类
                Map<String, Object> row = createRow(idx++, deliveryTask.getDeliveryDate(), deliveryTask.getDeliveryStartTime(), deliveryTask.getOrderCount(), orderAmountInYuan, deliveryCost, additionalFeeInYuan, deductFeeInYuan, totalFeeInYuan, note);
                data.add(row);
            }

            // 如果查出来的历史数据列表是空的，则在 excel 中添加一行空数据，防止生成一张空的 excel 引起歧义
            if (deliveryTaskList.isEmpty()) {
                Map<String, Object> emptyRow = createEmptyRow();
                data.add(emptyRow);
            }

            // 写入数据
            addSheet(writer, month, data, firstSheet);
            // 设置文件名为当前时间戳
            String filename = System.currentTimeMillis() + ".xlsx";

            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + filename);
            writer.flush(response.getOutputStream(), true);
        } catch (Exception e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw new RuntimeException("Error while generating Excel file", e);
        }
    }

    private void addSheet(ExcelWriter writer, String sheetName, List<Map<String, Object>> data, boolean firstSheet) {
        if (firstSheet) {
            writer.renameSheet(sheetName);
        } else {
            writer.setSheet(sheetName);
        }
        writer.write(data, true);

        // 获取当前工作表
        Sheet sheet = writer.getSheet();

        // 设置 "日期" 这一列的宽度，索引从 0 开始
        int dateColumnIndex = 1;
        sheet.setColumnWidth(dateColumnIndex, 12 * 256);

        // 设置 "配送开始时间" 这一列的宽度
        int storeNameColumnIndex = 2;
        sheet.setColumnWidth(storeNameColumnIndex, 12 * 256);

        // 设置 "配送开始时间" 这一列的宽度
        int deliveryCostColumnIndex = 5;
        sheet.setColumnWidth(deliveryCostColumnIndex, 12 * 256);

        // 设置 "备注" 这一列的宽度
        int noteColumnIndex = 9;
        sheet.setColumnWidth(noteColumnIndex, 60 * 256);
    }

    private Map<String, Object> createEmptyRow() {
        // 使用 LinkedHashMap 而不是 HashMap 防止标题栏乱序
        Map<String, Object> row = new LinkedHashMap<>();
        row.put("序号", null);
        row.put("日期", null);
        row.put("配送开始时间", null);
        row.put("订单数量", null);
        row.put("订单金额", null);
        row.put("结算方式", null);
        row.put("费用加项", null);
        row.put("扣除项", null);
        row.put("合计", null);
        row.put("备注", null);
        return row;
    }

    private Map<String, Object> createRow(Integer index, String date, String deliveryStartTime, Integer orderCount, String orderAmount, String deliveryCost, String additionalFee, String deductFee, String total, String note) {
        // 使用 LinkedHashMap 而不是 HashMap 防止标题栏乱序
        Map<String, Object> row = new LinkedHashMap<>();
        row.put("序号", index);
        row.put("日期", date);
        row.put("配送开始时间", deliveryStartTime);
        row.put("订单数量", orderCount);
        // 数值类数据转换成 BigDecimal，放置 excel 中该单元格显示感叹号
        row.put("订单金额", new BigDecimal(orderAmount));
        row.put("结算方式", deliveryCost);
        row.put("费用加项", new BigDecimal(additionalFee));
        row.put("扣除项", new BigDecimal(deductFee));
        row.put("合计", new BigDecimal(total));
        row.put("备注", note);
        return row;
    }
}
